package com.witdata.common.service.subject.impl;

import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.mybatisflex.core.query.QueryWrapper;
import com.witdata.common.domain.Status;
import com.witdata.common.domain.dto.QuestionDto;
import com.witdata.common.domain.dto.SqlCheckDto;
import com.witdata.common.domain.dto.SubjectQuestionDto;
import com.witdata.common.domain.req.SQLCompareRequest;
import com.witdata.common.domain.res.SQLSimilarityResponse;
import com.witdata.common.exception.GlobalException;
import com.witdata.common.mapper.SubjectMapper;
import com.witdata.common.service.subject.QuestionService;
import com.witdata.common.util.IdUtils;
import com.witdata.mysql.base.service.QuestionBaseService;
import com.witdata.mysql.base.service.SqlCheckBaseService;
import com.witdata.mysql.base.service.SubjectQuestionBaseService;
import com.witdata.mysql.domain.entity.TQuestion;
import com.witdata.mysql.domain.entity.TSqlCheck;
import com.witdata.mysql.domain.entity.TSubjectQuestion;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

@Service
@RequiredArgsConstructor
@Slf4j
public class QuestionServiceImpl implements QuestionService {
    private final QuestionBaseService questionBaseService;
    private final SubjectQuestionBaseService subjectQuestionBaseService;
    private final SqlCheckBaseService sqlCheckBaseService;

    @Override
    public List<QuestionDto> getQuestionListBySubjectId(Long subjectId, String type) {
        QueryWrapper queryWrapper = new QueryWrapper().eq("subject_id", subjectId);
        List<TSubjectQuestion> tSubjectQuestionList = subjectQuestionBaseService.list(queryWrapper);
        if (CollectionUtils.isEmpty(tSubjectQuestionList)) return List.of();
        List<Long> idList = tSubjectQuestionList.stream().map(TSubjectQuestion::getQuestionId).toList();
        QueryWrapper queryWrapper1 = new QueryWrapper().in("id", idList);
        if (StringUtils.hasText(type)) {
            queryWrapper1.eq("type", type);
        }
        List<TQuestion> tQuestionList = questionBaseService.list(queryWrapper1);
        if (CollectionUtils.isEmpty(tQuestionList)) return List.of();
        return SubjectMapper.INSTANCE.toQuestionDtoList(tQuestionList);
    }

    @Override
    public List<QuestionDto> getQuestionListBySubjectId(Long subjectId) {
        return getQuestionListBySubjectId(subjectId, null);
    }

    @Override
    @Transactional
    public void createQuestion(SubjectQuestionDto subjectQuestionDto) {
        Long questionId = IdUtils.createId();
        boolean save = subjectQuestionBaseService.save(TSubjectQuestion.builder()
                .id(IdUtils.createId())
                .subjectId(subjectQuestionDto.getSubjectId())
                .questionId(questionId)
                .joined(LocalDateTime.now())
                .build());
        TQuestion tQuestion = SubjectMapper.INSTANCE.toTQuestion(subjectQuestionDto.getQuestion());
        tQuestion.setId(questionId);
        tQuestion.setCreated(LocalDateTime.now());
        tQuestion.setUpdated(LocalDateTime.now());
        boolean save1 = questionBaseService.save(tQuestion);
        if (!save || !save1) {
            throw new GlobalException(Status.CREATEERROR);
        }
    }

    @Override
    @Transactional
    public void deleteQuestionById(Long questionId) {
        boolean removed = subjectQuestionBaseService.remove(new QueryWrapper().eq("question_id", questionId));
        boolean removed1 = questionBaseService.removeById(questionId);
        if (!removed || !removed1) throw new GlobalException(Status.DELETEERROR);
    }

    @Override
    public List<QuestionDto> getLatestQuestionListBySubjectId(Long subjectId, String type) {
        List<QuestionDto> questionDtoList = getQuestionListBySubjectId(subjectId, type);
        if (CollectionUtils.isEmpty(questionDtoList)) return List.of();
        questionDtoList.sort(Comparator.comparing(QuestionDto::getUpdated));
        return questionDtoList;
    }

    @Override
    public List<QuestionDto> getLatestQuestionListBySubjectId(Long subjectId) {
        return getLatestQuestionListBySubjectId(subjectId, null);
    }

    @Override
    public QuestionDto getQuestionInfo(Long id) {
        TQuestion tQuestion = questionBaseService.getById(id);
        return SubjectMapper.INSTANCE.toQuestionDto(tQuestion);
    }

    @Override
    public List<QuestionDto> getQuestionListByType(String type) {
        List<TQuestion> questionList = questionBaseService.list(new QueryWrapper().eq("type", type));
        if (!CollectionUtils.isEmpty(questionList)) {
            return SubjectMapper.INSTANCE.toQuestionDtoList(questionList);
        }
        return null;
    }

    /**
     * 验证答案
     * @param questionId
     * @param userAnswer
     * @return
     */
    @Override
    public boolean validateAnswer(Long questionId, String[] userAnswer) {
        TQuestion question = questionBaseService.getById(questionId);
        // 判断题目是否存在
        if (question != null) {
            // 1. 获取correctAnswer
            JSONObject jsonObj = JSONUtil.parseObj(question.getAnswer());
            JSONArray correctAnswerArray = jsonObj.getJSONArray("correctAnswer");
            // 2. 安全转换为String数组（避免ClassCastException）
            String[] answers = correctAnswerArray.stream()
                    .map(Object::toString)
                    .toArray(String[]::new);
            // 判断答案是否与用户答案一致
            for (int i=0; i<answers.length; i++) {
                if(!userAnswer[i].equals(answers[i])){
                    return false;
                }
            }
        }
        return true;
    }

    @Override
    public void checkSqlContent(SqlCheckDto sqlCheckDto) {
        System.out.println("sqlCheckDto = " + sqlCheckDto);
        QueryWrapper queryWrapper = new QueryWrapper()
                .eq("question_id", sqlCheckDto.getQuestionId());
        List<TSqlCheck> list = sqlCheckBaseService.list(queryWrapper);
        if (CollectionUtils.isEmpty(list)) sqlCheckBaseService.save(TSqlCheck.builder()
                        .id(IdUtils.createId())
                        .userId(sqlCheckDto.getUserId())
                        .subjectId(sqlCheckDto.getSubjectId())
                        .questionId(sqlCheckDto.getQuestionId())
                        .content(sqlCheckDto.getContent())
                        .multiplicity(0f)
                        .createTime(LocalDateTime.now())
                .build());
        else {
            AtomicReference<Float> similarity = new AtomicReference<>(0f);
            list.forEach(item -> {
                SQLCompareRequest sqlCompareRequest = SQLCompareRequest.builder()
                        .sql1(sqlCheckDto.getContent())
                        .sql2(item.getContent())
                        .build();
                String result2 = HttpRequest.post("http://localhost:8000/compare-sql")
                        .body(JSON.toJSONString(sqlCompareRequest))
                        .execute().body();
                SQLSimilarityResponse sqlSimilarityResponse = JSON.parseObject(result2, SQLSimilarityResponse.class);
                similarity.set((similarity.get() + sqlSimilarityResponse.getSimilarity()) / 2);
            });
            sqlCheckBaseService.save(TSqlCheck.builder()
                    .id(IdUtils.createId())
                    .userId(sqlCheckDto.getUserId())
                    .subjectId(sqlCheckDto.getSubjectId())
                    .questionId(sqlCheckDto.getQuestionId())
                    .content(sqlCheckDto.getContent())
                    .multiplicity(similarity.get())
                    .createTime(LocalDateTime.now())
                    .build());
        }

    }
}
